import { http } from "@/utils/http";
import type { ApiResponse } from "../user";
import { ensureArray, normalisePagination, toNumber } from "@/api/_helpers";
import { handleTree } from "@/utils/tree";

const PERMISSION_BASE = "/system/permission";

export interface PermissionListParams {
  page?: number;
  page_size?: number;
  keyword?: string;
  client_type?: string;
  status?: number | string;
  type?: string;
}

export interface PermissionItem {
  id: number;
  name: string;
  code: string;
  type: string;
  client_type: string;
  status: number;
  description?: string | null;
  parent_id?: number | null;
  sort?: number | null;
  created_at?: string | null;
  updated_at?: string | null;
}

export interface PermissionPayload {
  name: string;
  code: string;
  type: string;
  client_type?: string;
  status?: number;
  description?: string | null;
  parent_id?: number | null;
  sort?: number | null;
  role_ids?: Array<number>;
}

export interface PermissionListResult {
  list: Array<PermissionItem>;
  total: number;
  pageSize: number;
  currentPage: number;
  raw?: any;
}

export interface PermissionNode extends PermissionItem {
  children?: Array<PermissionNode>;
}

const mapPermission = (item: Record<string, any>): PermissionItem => ({
  id: toNumber(item.id, 0),
  name: item.name ?? "",
  code: item.code ?? "",
  type: item.type ?? "action",
  client_type: item.client_type ?? "admin",
  status: toNumber(item.status ?? 1, 1),
  description: item.description ?? "",
  parent_id: item.parent_id ?? item.parentId ?? null,
  sort: item.sort ?? null,
  created_at: item.create_time ?? item.created_at ?? "",
  updated_at: item.update_time ?? item.updated_at ?? ""
});

const mapPermissionNode = (item: Record<string, any>): PermissionNode => {
  const base = mapPermission(item);
  const childrenSource = ensureArray<Record<string, any>>(
    item.children ?? item.nodes ?? []
  );
  return {
    ...base,
    children: childrenSource.length
      ? childrenSource.map(mapPermissionNode)
      : undefined
  };
};

const buildTreeFromFlatList = (
  list: Array<PermissionItem>
): Array<PermissionNode> => {
  const tree = handleTree(
    list.map(item => ({ ...item })),
    "id",
    "parent_id",
    "children"
  ) as Array<PermissionNode>;

  const normaliseChildren = (nodes: Array<PermissionNode>) =>
    nodes.map(node => ({
      ...node,
      children: Array.isArray(node.children)
        ? normaliseChildren(node.children as Array<PermissionNode>)
        : undefined
    }));

  return normaliseChildren(tree);
};

const fetchList = async (
  params: PermissionListParams = {}
): Promise<PermissionListResult> => {
  const page = toNumber(params.page, 1);
  const pageSize = toNumber(params.page_size, 10);
  const response = await http.request<ApiResponse<any>>(
    "get",
    PERMISSION_BASE,
    {
      params: {
        ...params,
        page,
        page_size: pageSize
      }
    }
  );

  const payload = (response?.data as Record<string, any>) ?? {};
  const listSource =
    payload.list ?? payload.data ?? payload.records ?? payload.items ?? [];
  const list = ensureArray<Record<string, any>>(listSource).map(mapPermission);
  const pagination = normalisePagination(
    payload.pagination ?? payload,
    page,
    pageSize,
    list.length
  );

  return {
    list,
    total: pagination.total,
    pageSize: pagination.pageSize,
    currentPage: pagination.currentPage,
    raw: payload
  };
};

const fetchAll = async (
  params: PermissionListParams = {}
): Promise<Array<PermissionItem>> => {
  const { list } = await fetchList({
    ...params,
    page: 1,
    page_size: 1000
  });
  return list;
};

const fetchTree = async (
  params: PermissionListParams = {}
): Promise<Array<PermissionNode>> => {
  const fallback = async () => {
    const { list } = await fetchList(params);
    return buildTreeFromFlatList(list);
  };

  try {
    const response = await http.request<ApiResponse<any>>(
      "get",
      `${PERMISSION_BASE}/tree`,
      {
        params
      }
    );
    const payload = (response?.data as Record<string, any>) ?? {};
    const treeSource =
      payload.tree ??
      payload.list ??
      payload.data ??
      payload.records ??
      payload.items ??
      payload;
    const source = ensureArray<Record<string, any>>(treeSource);
    if (!source.length) {
      return await fallback();
    }
    return source.map(mapPermissionNode);
  } catch (error) {
    console.warn("fetch permission tree failed, fallback to list", error);
    return await fallback();
  }
};

const create = async (payload: PermissionPayload): Promise<PermissionItem> => {
  const res = await http.request<ApiResponse<any>>("post", PERMISSION_BASE, {
    data: payload
  });
  const data = (res?.data as Record<string, any>) ?? {};
  return mapPermission(data);
};

const update = async (
  id: number,
  payload: PermissionPayload
): Promise<PermissionItem> => {
  const res = await http.request<ApiResponse<any>>(
    "put",
    `${PERMISSION_BASE}/${id}`,
    {
      data: payload
    }
  );
  const data = (res?.data as Record<string, any>) ?? {};
  return mapPermission(data);
};

const remove = async (id: number): Promise<boolean> => {
  const res = await http.request<ApiResponse<any>>(
    "delete",
    `${PERMISSION_BASE}/${id}`
  );
  if (typeof res?.data === "boolean") return res.data;
  if (res?.success !== undefined) return Boolean(res.success);
  return true;
};

export default {
  fetchList,
  fetchAll,
  fetchTree,
  create,
  update,
  remove
};
